#!/usr/local/bin/perl -w
use strict;
use utf8;
use open qw(:std :utf8);

use lib '../lib';

use NG::Sys::App 'NG::Sys::Loop::Run';

use Benchmark qw(timethis cmpthese);
use NG::Sys::Cached::Mixed;
use NG::Sys::Cached::DBRow;
use NG::Sys::Cached::DBRowName;
use NG::Sys::Cached::DBColumn;
use NG::Sys::Cached::DBColumnAny;
use NG::Sys::Cached::DBColumnMulti;
use NG::Sys::Cached::MemColumnAny;

use NG::Sys::Cfg;

use JSON::XS;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
use Test::More 'no_plan';

my $app = new NG::Sys::App;
$app->ext_die;

$app->run;

sub on_process {
	$app->{cfg}{path}{cache} = "/tmpfs";
	$app->{cfg}{db}{two} = config("db_test");
	my $dbh = $app->dbh_to("two");
	#test_row($dbh);
	test_row_name($dbh);
	#test_col($dbh);
	#test_col_any($dbh);
	#test_col_mul($dbh);
	#test_col_any_mem();
	test_mixed($dbh);
}
sub test_row {
	my ($dbh) = @_;
	my $cache = $app->get_cache(fastmmap => {
		filename => "row.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";
	$dbh->exec("drop table if exists `c_row`");
	$dbh->exec("
CREATE TABLE `c_row` (
  `entry` int(11) NOT NULL,
  `i` int(11),
  `s` varchar(255) ,
  PRIMARY KEY (`entry`)
)");
	my $row = NG::Sys::Cached::DBRow->new(
		app => $app,
		cache => $cache,
		table => "c_row",
		namespace => "c_row",
		fields => ["i","s"],
		pkey => "entry",
		dbh => $dbh,
	);
	ok $row, "has row";
	is $row->{cache}->prefix, "c_row:", "valid prefix";
	$app->drop_context;
	my $o = $row->create({entry=>1});
	ok $o, "has object";
	my $rh = $dbh->row_hash("select * from c_row where entry=1");
	ok $rh, "row inserted";
	is $rh->{entry}, 1, "entry";
	ok ! defined $rh->{i},"i";
	ok ! defined $rh->{s},"s";
	ok $o->s("test"), "stored";
	$rh = $dbh->row_hash("select * from c_row where entry=1");
	is $rh->{s}, "test", "stored correctly";
	my $fc = $row->{cache}->get("1");
	ok $fc,"in cache";
	$fc = decode_json($fc);
	ok $fc,"valid cache";
	is $fc->{s}, "test", "cache stored correctly";
	is $o->s, "test", "data correctly";
	$app->drop_context;
	is $o->s, "test", "data correctly";
	$app->drop_context;
	$row->{cache}->remove("1");
	$fc = $row->{cache}->get("1");
	ok !$fc,"no in cache";
	is $o->s, "test", "data correctly";
	$o->clear_cache;
	ok !$row->{cache}->get("1"),"cache empty";
	$o->remove;

	ok $o = $row->create({entry=>1}), "has object";
	ok $o->update_data(i=>15,s=>"string"), "updated";
	$o->clear_cache;
	is $o->i,15,"correct";
	is $o->s,"string","correct";
	ok 1,"*************** row tested ok";
}
sub test_row_name {
	my ($dbh) = @_;
	my $cache = $app->get_cache(fastmmap => {
		filename => "rowname.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";
	$dbh->exec("drop table if exists `c_row_name`");
	$dbh->exec("
CREATE TABLE `c_row_name` (
  `entry` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `ii` int(11),
  `ss` varchar(255) ,
  PRIMARY KEY (`entry`),
  UNIQUE KEY `name` (`name`)
)");
	my $row = NG::Sys::Cached::DBRowName->new(
		app => $app,
		cache => $cache,
		table => "c_row_name",
		namespace => "c_row_name",
		fields => ["name","ii","ss"],
		pkey => "entry",
		nkey => "name",
		dbh => $dbh,
	);
	ok $row, "has row";
	is $row->{cache}->prefix, "c_row_name:", "valid prefix";
	$app->drop_context;
	ok my $o = $row->create({entry=>1,name=>"test"}), "has object";
	ok my $rh = $dbh->row_hash("select * from c_row_name where entry=1"), "row inserted";
	is $rh->{entry}, 1, "entry";
	is $rh->{name},"test","name";
	ok ! defined $rh->{ii},"ii";
	ok ! defined $rh->{ss},"ss";
	ok $o->ss("test"), "stored";
	$rh = $dbh->row_hash("select * from c_row_name where entry=1");
	is $rh->{ss}, "test", "stored correctly";
	ok my $fc = $row->{cache}->get("1"),"in cache";
	$fc = decode_json($fc);
	ok $fc,"valid cache";
	is $fc->{ss}, "test", "cache stored correctly";
	is $o->ss, "test", "data correctly";
	$app->drop_context;
	is $o->ss, "test", "data correctly";
	$app->drop_context;
	$row->{cache}->remove("1");
	ok !$row->{cache}->get("1"),"no in cache";
	is $o->ss, "test", "data correctly";
	is $row->{cache}->get("{1}"),"[test]", "id to name";
	is $row->{cache}->get("[test]"),"1", "name to id";
	is 1 , $row->check_for_name("test"), "check name";
	is 0 , $row->check_for_name("test2"), "check name";
	my $no;
	ok !$row->get_by_name("test2"), "not found by name";
	ok $no = $row->get_by_name("test"), "found by name";
	is $no->ss,"test"," valid value";
	ok $no->ii(15),"store ii";
	is $no->ii,$o->ii,"compare";
	$app->drop_context;
	is $no->ii,$o->ii,"compare without context";
	$o->clear_cache;
	ok !$row->{cache}->get("1"),"cache empty";
	ok !$row->{cache}->get("{1}"),"cache empty";
	ok !$row->{cache}->get("[test]"),"cache empty";
	$app->drop_context;
	is $o->ss,"test","validate";
	$o->remove;
	ok !$row->{cache}->get("1"),"cache empty after remove";
	ok !$row->{cache}->get("{1}"),"cache empty after remove";
	ok !$row->{cache}->get("[test]"),"cache empty after remove";
	ok !$dbh->row_hash("select * from c_row_name where entry=1"),"row delete";
	is $o->obj_id,1,"valid object";
	ok !$o->ss,"no data";
	no warnings;
	ok my $n = $row->create({entry=>2,name=>"Тест"}), "has object Тест";
	ok $row->check_for_name("Тест"), "found Тест";
	ok !$row->check_for_name("Тест2"), "not found Тест2";
	ok $row->check_for_name("ТЕСТ"), "found ТЕСТ";

	ok !$row->get_by_name("ТЕСТ"), "not get ТЕСТ";

	ok 1,"*************** row_name tested ok";
}
sub test_col {
	my ($dbh) = @_;
	my $cache = $app->get_cache(fastmmap => {
		filename => "row.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";
	$dbh->exec("drop table if exists `c_col`");
	$dbh->exec("
CREATE TABLE `c_col` (
  `entry` INT(11) NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `value` VARCHAR(255),
  PRIMARY KEY (`entry`,`name`)
)
");
	my $row = NG::Sys::Cached::DBColumn->new(
		app => $app,
		cache => $cache,
		table => "c_col",
		namespace => "c_col",
		fields => ["i","s"],
		pkey => "entry",
		nkey => "name",
		vkey => "value",
		dbh => $dbh,
	);
	ok $row, "has row";
	is $row->{cache}->prefix, "c_col:", "valid prefix";
	$app->drop_context;

	ok my $o = $row->get_obj(1), "has object";
	my $rh = $dbh->row_hash("select * from c_col where entry=1");
	ok !$rh, "no row";
	ok ! defined $o->i,"i";
	ok ! defined $o->s,"s";

	ok $o->s("test"), "stored";
	$rh = $dbh->rows_hash("select * from c_col where entry=1");
	is @$rh, 1, "one record";

	ok $o->i("test1"), "stored";
	$rh = $dbh->rows_hash("select * from c_col where entry=1");
	is @$rh, 2, "two record";

	my $fc = $row->{cache}->get("1");
	ok $fc,"in cache";
	$fc = decode_json($fc);
	ok $fc,"valid cache";
	is $fc->{s}, "test", "cache stored correctly";
	is $fc->{i}, "test1", "cache stored correctly";
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";
	
	$app->drop_context;
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";
	$app->drop_context;

	$row->{cache}->remove("1");
	$fc = $row->{cache}->get("1");
	ok !$fc,"no in cache";
	is $o->s, "test", "data correctly";

	$o->clear_cache;
	ok !$row->{cache}->get("1"),"cache empty";
	$app->drop_context;
	is $o->obj_id, 1, "data correctly";
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";
	$o->remove;
	$rh = $dbh->rows_hash("select * from c_col where entry=1");
	is @$rh, 0, "no record";
	ok !$row->{cache}->get("1"),"no in cache";

	ok $o = $row->get_obj(1), "has object";
	ok $o->update_data(i=>15,s=>"string"), "updated";
	$o->clear_cache;
	is $o->i,15,"correct";
	is $o->s,"string","correct";
	
	ok 1,"*************** col tested ok";
}

sub test_col_any {
	my ($dbh) = @_;
	my $cache = $app->get_cache(fastmmap => {
		filename => "row.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";
	$dbh->exec("drop table if exists `c_col_any`");
	$dbh->exec("
CREATE TABLE `c_col_any` (
  `entry` INT(11) NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `value` VARCHAR(255),
  PRIMARY KEY (`entry`,`name`)
)
");
	my $row = NG::Sys::Cached::DBColumnAny->new(
		app => $app,
		cache => $cache,
		table => "c_col_any",
		namespace => "c_col_any",
		pkey => "entry",
		nkey => "name",
		vkey => "value",
		dbh => $dbh,
	);
	ok $row, "has row";
	is $row->{cache}->prefix, "c_col_any:", "valid prefix";
	$app->drop_context;

	ok my $o = $row->get_obj(1), "has object";
	my $rh = $dbh->row_hash("select * from c_col_any where entry=1");
	ok !$rh, "no row";
	ok ! defined $o->i,"i";
	ok ! defined $o->s,"s";

	ok $o->s("test"), "stored";
	$rh = $dbh->rows_hash("select * from c_col_any where entry=1");
	is @$rh, 1, "one record";

	ok $o->i("test1"), "stored";
	$rh = $dbh->rows_hash("select * from c_col_any where entry=1");
	is @$rh, 2, "two record";

	my $fc = $row->{cache}->get("1");
	ok $fc,"in cache";
	$fc = decode_json($fc);
	ok $fc,"valid cache";
	is $fc->{s}, "test", "cache stored correctly";
	is $fc->{i}, "test1", "cache stored correctly";
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";
	
	$app->drop_context;
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";

	ok $o->i(undef), "stored";
	$rh = $dbh->rows_hash("select * from c_col_any where entry=1");
	is @$rh, 1, "one record";

	$app->drop_context;

	$row->{cache}->remove("1");
	$fc = $row->{cache}->get("1");
	ok !$fc,"no in cache";
	is $o->s, "test", "data correctly";

	$o->clear_cache;
	ok !$row->{cache}->get("1"),"cache empty";
	$app->drop_context;
	is $o->obj_id, 1, "data correctly";
	is $o->s, "test", "data correctly";
	ok !defined $o->i, "data correctly";
	$o->remove;
	$rh = $dbh->rows_hash("select * from c_col_any where entry=1");
	is @$rh, 0, "no record";
	ok !$row->{cache}->get("1"),"no in cache";

	ok $o = $row->get_obj(1), "has object";
	ok $o->update_data(i=>15,s=>"string"), "updated";
	$o->clear_cache;
	is $o->i,15,"correct";
	is $o->s,"string","correct";


	ok 1,"*************** col tested ok";
}

sub test_col_mul {
	my ($dbh) = @_;
	my $cache = $app->get_cache(fastmmap => {
		filename => "row.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";
	$dbh->exec("drop table if exists `c_col_mul`");
	$dbh->exec("
CREATE TABLE `c_col_mul` (
  `entry` INT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `num` int,
  `str` VARCHAR(255),
  PRIMARY KEY (`entry`,`name`)
)
");
	my $row = NG::Sys::Cached::DBColumnMulti->new(
		app => $app,
		cache => $cache,
		table => "c_col_mul",
		namespace => "c_col_mul",
		fields => ["i","s"],
		pkey => "entry",
		nkey => "name",
		vkey => ["num","str"],
		dbh => $dbh,
	);
	ok $row, "has col_mul";
	is $row->{cache}->prefix, "c_col_mul:", "valid prefix";
	$app->drop_context;

	ok my $o = $row->get_obj(1), "has object";
	ok ! defined $o->i, "no data";
	ok !( my $rh = $dbh->row_hash("select * from c_col_mul where entry=1")), "no row";

	ok $o->i([10,"test"]),"stored";

	is ref $o->i, "ARRAY", "is array";
	is @{$o->i}, 2,"2 elements";
	is $o->i->[0], 10," one valid";
	is $o->i->[1], "test"," second valid";


	ok my $fc = $row->{cache}->get("1"),"in cache";
	$fc = decode_json($fc);
	ok $fc,"valid cache";
	is $fc->{i}[0], 10, "cache stored correctly";
	is $fc->{i}[1], "test", "cache stored correctly";
	is $o->i->[0], 10, "data correctly";
	is $o->i->[1], "test", "data correctly";

	$app->drop_context;
	is $o->i->[0], 10, "data correctly";
	is $o->i->[1], "test", "data correctly";

	$o->clear_cache;
	is $o->i->[0], 10, "data correctly";
	is $o->i->[1], "test", "data correctly";

	$o->remove;
	$rh = $dbh->rows_hash("select * from c_col_mul where entry=1");
	is @$rh, 0, "no record";
	ok !$row->{cache}->get("1"),"no in cache";
	ok 1,"*************** col_mul tested ok";
}

sub test_mixed {
	my ($dbh) = @_;
	my $cache = $app->get_cache(fastmmap => {
		filename => "row.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";


	$dbh->exec("drop table if exists `mixed_row`");
	$dbh->exec("
CREATE TABLE `mixed_row` (
  `entry` int(11) NOT NULL,
  `ir` int(11),
  `sr` varchar(255) ,
  PRIMARY KEY (`entry`)
)
");

	$dbh->exec("drop table if exists `mixed_row_name`");
	$dbh->exec("
CREATE TABLE `mixed_row_name` (
  `entry` int(11) AUTO_INCREMENT NOT NULL,
  `nn` varchar(255) NOT NULL,
  `in` int(11),
  `sn` varchar(255) ,
  PRIMARY KEY (`entry`),
  UNIQUE KEY `name` (`nn`)
)
");

	$dbh->exec("drop table if exists `mixed_row_name2`");
	$dbh->exec("
CREATE TABLE `mixed_row_name2` (
  `entry` int(11) NOT NULL,
  `nn2` varchar(255) NOT NULL,
  `in2` int(11),
  `sn2` varchar(255) ,
  PRIMARY KEY (`entry`),
  UNIQUE KEY `name` (`nn2`)
)
");

	$dbh->exec("drop table if exists `mixed_col`");
	$dbh->exec("
CREATE TABLE `mixed_col` (
  `entry` INT(11) NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `value` VARCHAR(255),
  PRIMARY KEY (`entry`,`name`)
)
");

	$dbh->exec("drop table if exists `mixed_col_blob`");
	$dbh->exec("
CREATE TABLE `mixed_col_blob` (
  `entry` INT(11) NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `value` blob,
  PRIMARY KEY (`entry`,`name`)
)
");

	$dbh->exec("drop table if exists `mixed_col_mul`");
	$dbh->exec("
CREATE TABLE `mixed_col_mul` (
  `entry` INT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `num` int,
  `str` VARCHAR(255),
  PRIMARY KEY (`entry`,`name`)
)
");

	$dbh->exec("drop table if exists `mixed_col_any`");
	$dbh->exec("
CREATE TABLE `mixed_col_any` (
  `entry` INT NOT NULL,
  `name` VARCHAR(255) NOT NULL,
  `str` VARCHAR(255),
  PRIMARY KEY (`entry`,`name`)
)
");

	my $mixed = new NG::Sys::Cached::Mixed(
		app => $app,
		dbh => $dbh,
		cache => $cache,
		namespace => "mix_main",
		compile => 1,
		subclass => 1,
		extern =>[
			{
				namespace => "values",
				table => "mixed_col_any",
				pkey => "entry",
				nkey => "name",
				vkey => "str",
				class => "NG::Sys::Cached::DBColumnAny",
				compile => 1,
				subclass => 1,
			}
		],
		tables => [
			{
				table => "mixed_row_name",
				fields => ["nn","in","sn"],
				pkey => "entry",
				nkey => "nn",
				class => "NG::Sys::Cached::DBRowName",
				creator => 1,
				searcher => 1,
		compile => 1,
		subclass => 1,
			},
			{
				table => "mixed_row_name2",
				fields => ["nn2","in2","sn2"],
				pkey => "entry",
				nkey => "nn2",
				class => "NG::Sys::Cached::DBRowName",
				searcher => 1,
		compile => 1,
		subclass => 1,
			},
			{
				table => "mixed_row",
				fields => ["ir","sr"],
				pkey => "entry",
				class => "NG::Sys::Cached::DBRow",
		compile => 1,
		subclass => 1,
			},
			{
				table => "mixed_col",
				fields => ["sc","vc"],
				pkey => "entry",
				nkey => "name",
				vkey => "value",
				class => "NG::Sys::Cached::DBColumn",
		compile => 1,
		subclass => 1,
			},
			{
				table => "mixed_col_blob",
				fields => ["sb","vb"],
				pkey => "entry",
				nkey => "name",
				vkey => "value",
				blobs => ["sb","vb"],
				class => "NG::Sys::Cached::DBColumn",
		compile => 1,
		subclass => 1,
			},
			{
				table => "mixed_col_mul",
				fields => ["sm","vm"],
				pkey => "entry",
				nkey => "name",
				vkey => ["num","str"],
				class => "NG::Sys::Cached::DBColumnMulti",
		compile => 1,
		subclass => 1,
			},
		],
	);

	ok $mixed, "has mixed";
	is $mixed->{cache}->prefix, "mix_main:", "valid prefix";
	for my $ns (qw(
			mixed_row_name
			mixed_row_name2
			mixed_row
			mixed_col
			mixed_col_mul
		)){
		my $pos = $mixed->{table_pos}{$ns};
		my $t = $mixed->{_tables}[$pos]{object};
		is $t->{cache}->prefix, $ns.":", "prefix $ns";
	}
	ok my $o = $mixed->create(0,{nn=>"first",nn2=>"second"}),"has object";
	is $o->nn,"first","correct value";
	is $o->nn2,"second","correct value";
	$o->clear_cache;
	is $o->obj_id,1,"entry";
	$o = undef;
	$app->drop_context;
	ok $o = $mixed->get_obj(1),"get object";
	is $o->nn,"first","correct value";
	is $o->nn2,"second","correct value";
	ok $o->ir(10), "set ir";
	is $o->ir,10,"correct";
	ok $o->sr("sr"), "set sr";
	is $o->sr,"sr","correct";
	ok $o->sn("sn"), "set sn";
	is $o->sn,"sn","correct";
	ok $o->in(10), "set in";
	is $o->in,10,"correct";
	ok $o->sn2("sn2"), "set sn2";
	is $o->sn2,"sn2","correct";
	ok $o->in2(10), "set in2";
	is $o->in2,10,"correct";
	ok $o->sc("sc"), "set sc";
	is $o->sc,"sc","correct";
	ok $o->vc("vc"), "set vc";
	is $o->vc,"vc","correct";
	ok $o->sm([10,"sm"]), "set sm";
	is $o->sm->[0],10,"correct";
	is $o->sm->[1],"sm","correct";
	ok $o->vm([10,"vm"]), "set vm";
	is $o->vm->[0],10,"correct";
	is $o->vm->[1],"vm","correct";
	$app->drop_context;
	is $o->nn,"first","correct value nn";
	is $o->nn2,"second","correct value nn2";
	is $o->ir,10,"correct ir";
	is $o->sr,"sr","correct sr";
	is $o->sn,"sn","correct sn";
	is $o->in,10,"correct in";
	is $o->sn2,"sn2","correct sn2";
	is $o->in2,10,"correct in2";
	is $o->sc,"sc","correct sc";
	is $o->vc,"vc","correct vc";
	is $o->sm->[0],10,"correct sm0";
	is $o->sm->[1],"sm","correct sm1";
	is $o->vm->[0],10,"correct vm0";
	is $o->vm->[1],"vm","correct vm1";
	
	$o->clear_cache;
	is $o->nn,"first","correct value nn";
	is $o->nn2,"second","correct value nn2";
	is $o->ir,10,"correct ir";
	is $o->sr,"sr","correct sr";
	is $o->sn,"sn","correct sn";
	is $o->in,10,"correct in";
	is $o->sn2,"sn2","correct sn2";
	is $o->in2,10,"correct in2";
	is $o->sc,"sc","correct sc";
	is $o->vc,"vc","correct vc";
	is $o->sm->[0],10,"correct sm0";
	is $o->sm->[1],"sm","correct sm1";
	is $o->vm->[0],10,"correct vm0";
	is $o->vm->[1],"vm","correct vm1";
	
	ok my $no = $mixed->get_by_name("first"),"get by name object";
	ok !$mixed->get_by_name("first2"),"get by bad name object ";

	ok my $ko = $mixed->get_by_key("nn2","second"),"get by key object";
	ok !$mixed->get_by_key("nn2","second2"),"get by bad key object";
	
	$o->remove;
	ok !$mixed->get_by_key("nn2","second"),"get by bad key object";
	ok !$mixed->get_by_name("first"),"get by bad name object ";
	ok ! defined $no->nn,"correct value nn";
	ok ! defined $no->nn2,"correct value nn2";
	ok ! defined $ko->nn,"correct value nn";
	ok ! defined $ko->nn2,"correct value nn2";
	
	ok $o = $mixed->create(0,{nn=>"first",nn2=>"second"}),"has object";
	ok $o->update_data(ir=>15,sn=>"test",vc=>"demo",vm=>[100,"sto"]),"updated";
	ok $o->vc("Демо"),"store vc";
	$o->clear_cache;
	is $o->ir,15,"correct ir";
	is $o->sn,"test","correct sn";
	is $o->vc,"Демо","correct vc";
	is $o->vm->[0],100,"correct vm0";
	is $o->vm->[1],"sto","correct vm1";

	$o->drop_context;
	my @l = $o->read_data(['ir','sn','vc','vm']);
	is $l[0],15,"correct ir";
	is $l[1],"test","correct sn";
	is $l[2],"Демо","correct vc";
	is $l[3][0],100,"correct vm0";
	is $l[3][1],"sto","correct vm1";

	$o->drop_context;
	my $l = $o->read_data;
	is $l->{ir},15,"correct ir";
	is $l->{sn},"test","correct sn";
	is $l->{vc},"Демо","correct vc";
	is $l->{vm}->[0],100,"correct vm0";
	is $l->{vm}->[1],"sto","correct vm1";

	ok ! defined $l->{sb},"blob";
	ok $o->sb([0,1,{0=>1,2=>"Блоб"}]), "store";
	is $o->sb->[0],0,"correct 5";
	is $o->sb->[2]{2},"Блоб","correct 4";
	$o->drop_context;
	is $o->sb->[0],0,"correct 3";
	is $o->sb->[2]{2},"Блоб","correct 2";
	$o->clear_cache;
	is $o->sb->[0],0,"correct 1";
	is $o->sb->[2]{2},"Блоб","correct 0";

	ok $o->values ,"has values";
	ok $o->values->test(10),"values stored";
	is $o->values->test,10, " value right 1";
	$o->drop_context;
	is $o->values->test,10, " value right 2";
	$o->clear_cache;
	ok !defined (my $fc = $mixed->{cache}{cache}->get("values:2")),"not in cache after clear";
	is $o->values->test,10, " value right 3";
	
	ok $fc = $mixed->{cache}{cache}->get("values:2"),"in cache";
	ok $fc = decode_json($fc),"valid cache";
	is $fc->{test}, 10, "cache stored correctly";

	ok my $n = $mixed->create(0,{nn=>"Первый",nn2=>"Второй"}),"has new object";
	ok $mixed->check_for_name("ПЕРВЫЙ"), "has ПЕРВЫЙ";
	ok !$mixed->get_by_name("ПЕРВЫЙ"), "not get ПЕРВЫЙ";
	ok $n->in(33),"store in";
	
	my @d = $n->read_data(["nn","nn2","in"]);
	is $d[0], "Первый", "nn";
	is $d[1], "Второй", "nn2";
	is $d[2], 33, "in";
	

	ok 1,"*************** mixed tested ok";
}

sub test_col_any_mem {
	my $cache = $app->get_cache(fastmmap => {
		filename => "row.dat.".rand(),
		page_size => 4096,
		num_pages => 101,
		is_tmp => 1,
	});
	ok $cache, "has cache";
	my $row = NG::Sys::Cached::MemColumnAny->new(
		app => $app,
		cache => $cache,
		namespace => "c_col_any_mem",
	);
	ok $row, "has row";
	is $row->{cache}->prefix, "c_col_any_mem:", "valid prefix";
	$app->drop_context;

	ok my $o = $row->get_obj(1), "has object";
	ok ! defined $o->i,"i";
	ok ! defined $o->s,"s";

	ok $o->s("test"), "stored";
	ok $o->i("test1"), "stored";

	my $fc = $row->{cache}->get("1");
	ok $fc,"in cache";
	$fc = decode_json($fc);
	ok $fc,"valid cache";
	is $fc->{s}, "test", "cache stored correctly";
	is $fc->{i}, "test1", "cache stored correctly";
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";
	
	$app->drop_context;
	is $o->s, "test", "data correctly";
	is $o->i, "test1", "data correctly";

	$app->drop_context;
	$row->{cache}->remove("1");
	$fc = $row->{cache}->get("1");
	ok !$fc,"no in cache";
	ok !defined $o->s, "data correctly";

	$o->clear_cache;
	ok !$row->{cache}->get("1"),"cache empty";
	$app->drop_context;

	$o->remove;
	ok $o = $row->get_obj(1), "has object";
	ok $o->update_data(i=>15,s=>"string"), "updated";

	$app->drop_context;
	is $o->s, "string", "data correctly";
	is $o->i, 15, "data correctly";

	$o->clear_cache;
	ok !defined $o->i,"correct";
	ok !defined $o->s,"correct";

	ok 1,"*************** col_any_mem tested ok";
}
